#ifndef SGU_LINEAR3D_H
#define SGU_LINEAR3D_H

SGU_NS_BEGIN

//! Vector in \f$\Re^3\f$
/*! Vector is stored using its cartesian components namely \a x, \a y and \a z.
 *  \n This class in nearly-immutable: only serialize, assignment and compound assignment can change its state.
 *  \n Hereafter in this page:
 *  - v is used for vector
 *  - u is used for versor
 *  - k is used for scalar
 *  .
 *  - subsctipt 0 is used for \c this vector
 *  - subscript 1,2..n are used for parameters and for binary operators
 *  - subscript r is used for return value
 *  .
 */

class Vector3D : public Serializable  /// Vettore in 3D
{
	DECLARE_SERIALIZABLE(Vector3D)

	private:
	real _x,_y,_z;

	public:

	Vector3D() : _x(0), _y(0), _z(0) {}
	Vector3D(real px, real py, real pz) : _x(px),_y(py),_z(pz) {}
	explicit Vector3D(const Point3D & p);
	explicit Vector3D(const Versor3D & v);

	real x() const {return _x;}
	real y() const {return _y;}
	real z() const {return _z;}

	real operator ! () const {return ::sqrt(qdr());}
	real qdr() const {return (sqr(_x) + sqr(_y) + sqr(_z));}   
  
	const Vector3D & operator + () const {return *this;}                    
	const Vector3D operator - () const {return Vector3D(-_x,-_y,-_z);} 
	static const Vector3D O;                                    
   
	const Vector3D operator * (real k) const {return Vector3D(_x*k,_y*k,_z*k);}
	const Vector3D operator / (real k) const {return Vector3D(_x/k,_y/k,_z/k);}
	
	Vector3D & operator += (const Vector3D & v);                      
	Vector3D & operator -= (const Vector3D & v);
	Vector3D & operator *= (const Matrix33 & m);                        
 

	real operator * (const Vector3D & v) const {return _x*v._x + _y*v._y + _z*v._z;}
	const Vector3D operator ^ (const Vector3D & v) const; 
	const Vector3D operator + (const Vector3D & v) const {return Vector3D(_x+v._x,_y+v._y,_z+v._z);}  
	const Vector3D operator - (const Vector3D & v) const {return Vector3D(_x-v._x,_y-v._y,_z-v._z);}

	const Vector3D operator | (const Versor3D & u) const; 
	Vector3D & operator |= (const Versor3D & u); 

	real operator / (const Versor3D &) const;
	const Vector3D operator % (const Versor3D &) const;
	Vector3D & operator %= (const Versor3D &);

	void serialize(BOStorage &) const;
	void serialize(BIStorage &);
	void serialize(TOStorage &) const;
	void serialize(TIStorage &);
};



class Point3D : public Serializable
{
	DECLARE_SERIALIZABLE(Point3D)

	private:
	real _x,_y,_z;

	public:
	Point3D() : _x(real_NaN()), _y(real_NaN()), _z(real_NaN()) {}
	Point3D(real px, real py, real pz) : _x(px), _y(py), _z(pz) {}
	explicit Point3D(const Vector3D & v) : _x(v.x()), _y(v.y()), _z(v.z()) {}

	static const Point3D NaN;

	real x() const {return _x;}
	real y() const {return _y;}
	real z() const {return _z;}

	const Point3D operator | (const Line3D &) const;       
	const Point3D operator | (const Plane3D &) const;     
	Point3D & operator |= (const Line3D &);        
	Point3D & operator |= (const Plane3D &);      

	Point3D & operator += (const Vector3D & v);
	const Point3D operator + (const Vector3D & v) const;

	Point3D & operator -= (const Vector3D & v);
	const Point3D operator - (const Vector3D & v) const;
 
	Point3D & operator *= (const Transform3D & v);
	const Point3D operator * (const Transform3D & v) const;
	
	const Vector3D operator - (const Point3D & p) const;

	bool isFinite() const {return finite(_x) && finite(_y) && finite(_z);}

	void serialize(BOStorage &) const;
	void serialize(BIStorage &);
	void serialize(TOStorage &) const;
	void serialize(TIStorage &);
};

inline real dist2(const Point3D & p1, const Point3D & p2) {return (p2-p1).qdr();}
inline real dist(const Point3D & p1, const Point3D & p2) {return ::sqrt(dist2(p1,p2));}



class Matrix33 : public Serializable   
{
	DECLARE_SERIALIZABLE(Matrix33)

	public:

	real _m11,_m12,_m13,_m21,_m22,_m23,_m31,_m32,_m33;

	Matrix33() :
	 	_m11(0), _m12(0), _m13(0),
		_m21(0), _m22(0), _m23(0),
		_m31(0), _m32(0), _m33(0) {}
  
	Matrix33(real m11, real m12, real m13,
		     real m21, real m22, real m23,
			 real m31, real m32, real m33) :
		_m11(m11), _m12(m12), _m13(m13),
		_m21(m21), _m22(m22), _m23(m23),
		_m31(m31), _m32(m32), _m33(m33) {}
	
	Matrix33(const Vector3D & pc1, const Vector3D & pc2, const Vector3D & pc3) : 
	
		_m11(pc1.x()), _m12(pc2.x()), _m13(pc3.x()),
		_m21(pc1.y()), _m22(pc2.y()), _m23(pc3.y()),
		_m31(pc1.z()), _m32(pc2.z()), _m33(pc3.z()) {}

	real operator !() const
	{
		return 
		+ (_m11 * _m22 * _m33)
		- (_m11 * _m23 * _m32)
		- (_m12 * _m21 * _m33)
		+ (_m12 * _m23 * _m31)
		+ (_m13 * _m21 * _m32)
		- (_m13 * _m22 * _m31);
	}                        

	const Matrix33 operator *() const {return Matrix33(_m11,_m21,_m31,_m12,_m22,_m32,_m13,_m23,_m33);}
	const Matrix33 operator ~() const;   
	const Matrix33 & operator +() const {return *this;}
	const Matrix33 operator -() const {return Matrix33(-_m11,-_m12,-_m13,-_m21,-_m22,-_m23,-_m31,-_m32,-_m33);}
  

	const Matrix22 minor11() const {return Matrix22(_m22,_m23,_m32,_m33);}
	const Matrix22 minor12() const {return Matrix22(_m21,_m23,_m31,_m33);}
	const Matrix22 minor13() const {return Matrix22(_m21,_m22,_m31,_m32);}
	const Matrix22 minor21() const {return Matrix22(_m12,_m13,_m32,_m33);}
	const Matrix22 minor22() const {return Matrix22(_m11,_m13,_m31,_m33);}
	const Matrix22 minor23() const {return Matrix22(_m11,_m12,_m31,_m32);}
	const Matrix22 minor31() const {return Matrix22(_m12,_m13,_m22,_m23);}
	const Matrix22 minor32() const {return Matrix22(_m11,_m13,_m21,_m23);}
	const Matrix22 minor33() const {return Matrix22(_m11,_m12,_m21,_m22);}

	static const Matrix33 I; 
	static const Matrix33 O;

	const Vector3D operator * (const Vector3D & v) const; 
	//const Versor3D operator * (const Versor3D &) const;  
 
	const Matrix33 operator * (real k) const {return Matrix33(_m11*k,_m12*k,_m13*k,_m21*k,_m22*k,_m23*k,_m31*k,_m32*k,_m33*k);}
	const Matrix33 operator / (real k) const {return Matrix33(_m11/k,_m12/k,_m13/k,_m21/k,_m22/k,_m23/k,_m31/k,_m32/k,_m33/k);}

	const Matrix33 operator * (const Matrix33 & m) const; 
	const Matrix33 operator + (const Matrix33 & m) const;
	const Matrix33 operator - (const Matrix33 & m) const;
 
	Matrix33 & operator += (const Matrix33 & m);                      
	Matrix33 & operator -= (const Matrix33 & m);

	static const Matrix33 rotation(real theta, const Versor3D & n) {return Matrix33::rotation(::cos(theta),::sin(theta),n);}
	static const Matrix33 rotation(real costheta, real sintheta, const Versor3D & n);

    
	const Vector3D c1() const {return Vector3D(_m11,_m21,_m31);}
	const Vector3D c2() const {return Vector3D(_m12,_m22,_m32);}
	const Vector3D c3() const {return Vector3D(_m13,_m23,_m33);}

	void serialize(BOStorage &) const;
	void serialize(BIStorage &);
	void serialize(TOStorage &) const;
	void serialize(TIStorage &);
};

 
class Versor3D : public Serializable 
{
	DECLARE_SERIALIZABLE(Versor3D)

	private:
	real _x,_y,_z;
	void normalize() {real k = 1.0 / ::sqrt(sqr(_x)+sqr(_y)+sqr(_z)); _x *= k, _y *= k, _z *= k;}
	Versor3D(real px, real py, real pz, void*) : _x(px), _y(py), _z(pz) {}

	public:
	Versor3D() : _x(real_NaN()), _y(real_NaN()), _z(real_NaN()) {}
	Versor3D(real px, real py, real pz) : _x(px), _y(py), _z(pz) {normalize();}
	explicit Versor3D(const Vector3D & v) : _x(v.x()), _y(v.y()), _z(v.z()) {normalize();}
 
	//void set(real x, real y, real z) {_x=x,_y=y,_z=z;normalize();}
	//void setX(real x) {_x=x;normalize();}
	//void setY(real y) {_y=y;normalize();}
	//void setZ(real z) {_z=z;normalize();}

 	real x() const {return _x;}
	real y() const {return _y;}
	real z() const {return _z;}

	static const Versor3D X;
	static const Versor3D Y;
	static const Versor3D Z;

	static const Versor3D ort(const Versor3D & v1, const Versor3D & v2) {return Versor3D(Vector3D(v1)^Vector3D(v2));}
	static const Versor3D bisect(const Versor3D & v1, const Versor3D & v2) {return Versor3D(Vector3D(v1)+Vector3D(v2));}

	//! Opposite
	const Versor3D operator -() const {return Versor3D(-_x,-_y,-_z,NULL);}

	const Vector3D operator * (real k) const {return Vector3D(_x*k,_y*k,_z*k);}
	const Vector3D operator / (real k) const {return Vector3D(_x/k,_y/k,_z/k);}

	void serialize(BOStorage &) const;
	void serialize(BIStorage &);
	void serialize(TOStorage &) const;
	void serialize(TIStorage &);
};



class Line3D : public Serializable   
{
	DECLARE_SERIALIZABLE(Line3D)

	private:
	Point3D _p;	
	Versor3D _u;
	
	public:
	Line3D() {}
	Line3D(const Point3D & p, const Versor3D & u): _p(p), _u(u) {}
	Line3D(const Point3D & p1, const Point3D & p2);
	explicit Line3D(const Segment3D &);
	explicit Line3D(const SemiLine3D &);
  
	const Point3D & org() const {return _p;}
	const Versor3D & dir() const {return _u;}

	const Line3D operator | (const Plane3D &) const;
	Line3D & operator |= (const Plane3D &);

	Line3D & operator += (const Vector3D & v);
	const Line3D operator + (const Vector3D & v) const;
	
	Line3D & operator -= (const Vector3D & v);
	const Line3D operator - (const Vector3D & v) const;
	
	Line3D & operator *= (const Transform3D & v);
	const Line3D operator * (const Transform3D & v) const;

	void serialize(BOStorage &) const;
	void serialize(BIStorage &);
	void serialize(TOStorage &) const;
	void serialize(TIStorage &);
};


class SemiLine3D : public Serializable  
{
	DECLARE_SERIALIZABLE(SemiLine3D)

	private:
	Point3D _p;
	Versor3D _u; 

	public:
	SemiLine3D() {}
	SemiLine3D(const Point3D & p, const Versor3D & u): _p(p), _u(u) {}
	SemiLine3D(const Point3D & p1, const Point3D & p2);
	explicit SemiLine3D(const Segment3D &);
  
	const Point3D & org() const {return _p;}
	const Versor3D & dir() const {return _u;}

	const SemiLine3D operator | (const Plane3D &) const;
	SemiLine3D & operator |= (const Plane3D &);

	SemiLine3D & operator += (const Vector3D & v);
	const SemiLine3D operator + (const Vector3D & v) const;
	
	SemiLine3D & operator -= (const Vector3D & v);
	const SemiLine3D operator - (const Vector3D & v) const;
	
	SemiLine3D & operator *= (const Transform3D & v);
	const SemiLine3D operator * (const Transform3D & v) const;

	bool coproj(const Point3D & q) const {return ((q - _p) / _u >=0);}
};


class Plane3D : public Serializable 
{
	DECLARE_SERIALIZABLE(Plane3D)

	private:
	Point3D _p;
	Versor3D _n;

	public:	
	Plane3D() {}
	Plane3D(const Point3D & p, const Versor3D & n) : _p(p) , _n(n) {}
	explicit Plane3D(const Triangle3D & t);

	const Point3D & org() const {return _p;}
	const Versor3D & nrm() const {return _n;}

	Plane3D & operator += (const Vector3D & v);
	const Plane3D operator + (const Vector3D & v) const;
	
	Plane3D & operator -= (const Vector3D & v);
	const Plane3D operator - (const Vector3D & v) const;

	Plane3D & operator *= (const Transform3D & v);
	const Plane3D operator * (const Transform3D & v) const;

	void serialize(BOStorage &) const;
	void serialize(BIStorage &);
	void serialize(TOStorage &) const;
	void serialize(TIStorage &);

};


class Segment3D : public Serializable
{
	DECLARE_SERIALIZABLE(Segment3D)

	private:
	Point3D _a,_b;
	
	public:
	Segment3D() {}
	Segment3D(const Point3D & pa, const Point3D & pb) : _a(pa), _b(pb) {}

	const Point3D & a() const {return _a;}
	const Point3D & b() const {return _b;}

	Segment3D & operator += (const Vector3D & v);
	const Segment3D operator + (const Vector3D & v) const;
	
	Segment3D & operator -= (const Vector3D & v);
	const Segment3D operator - (const Vector3D & v) const;

	Segment3D & operator *= (const Transform3D & v);
	const Segment3D operator * (const Transform3D & v) const;

	const Segment3D operator | (const Line3D &) const;
	const Segment3D operator | (const Plane3D &) const;
	Segment3D & operator |= (const Line3D &);
	Segment3D & operator |= (const Plane3D &);

	bool coproj(const Point3D & p) const {return inco((p-_a)*(_b-_a),0.0,length2());}
	const Point3D middle() const;

	real length() const {return ::sqrt(length2());}
	real length2() const {return dist2(_a,_b);}

	void serialize(BOStorage &) const;
	void serialize(BIStorage &);
	void serialize(TOStorage &) const;
	void serialize(TIStorage &);
};

 
class Triangle3D : public Serializable  
{
	DECLARE_SERIALIZABLE(Triangle3D)

	public:
	Point3D _a,_b,_c;
	
	Triangle3D() {}
	Triangle3D(const Point3D & pa, const Point3D & pb, const Point3D & pc) :  _a(pa), _b(pb), _c(pc) {}

	const Point3D & a() const {return _a;}
 	const Point3D & b() const {return _b;}
	const Point3D & c() const {return _c;}

	const Point3D baricenter() const;
	const Vector3D operator !() const;

	Triangle3D & operator += (const Vector3D & v);
	const Triangle3D operator + (const Vector3D & v) const;
	
	Triangle3D & operator -= (const Vector3D & v);
	const Triangle3D operator - (const Vector3D & v) const;

	Triangle3D & operator *= (const Transform3D & v);
	const Triangle3D operator * (const Transform3D & v) const;

	const Triangle3D operator | (const Plane3D &) const;
	Triangle3D & operator |= (const Plane3D &);

	bool coproj(const Point3D & p) const;

	void serialize(BOStorage &) const;
	void serialize(BIStorage &);
	void serialize(TOStorage &) const;
	void serialize(TIStorage &);
};


class Size3D : public Serializable 
{
	DECLARE_SERIALIZABLE(Size3D)

	private:	
	real _x,_y,_z;
	void absolutize() {_x=fabs(_x),_y=fabs(_y),_z=fabs(_z);}

	public:
	Size3D() {}
	Size3D(real x, real y, real z) : _x(fabs(x)), _y(fabs(y)), _z(fabs(z)) {}
 
	//void set(real x, real y, real z) {_x=fabs(x),_y=fabs(y),_z=fabs(z);}
	//void setX(real x) {_x=fabs(x);}
	//void setY(real y) {_y=fabs(y);}
	//void setZ(real z) {_z=fabs(z);}

	//real getX() const {return _x;}
	//real getY() const {return _y;}
	//real getZ() const {return _z;}

	real volume() const {return _x*_y*_z;}

	void serialize(BOStorage &) const;
	void serialize(BIStorage &);
	void serialize(TOStorage &) const;
	void serialize(TIStorage &);
};

#if 0
class Box3D : public Serializable /// parallelepipedo parallelo agli assi (senza segno)
{
	public:
	Point3D a,b;
	
	explicit Box3D(const std::vector<Point3D> & k);
 
	void set(const std::vector<Point3D> &);
  
	Box3D & operator += (const Vector3D & v);
	Box3D operator + (const Vector3D & v) const;
	
	Box3D & operator -= (const Vector3D & v);
	Box3D operator - (const Vector3D & v) const;
 
	Box3D & operator *= (const Transform3D & v);
	Box3D operator * (const Transform3D & v) const;

	bool co(const Point3D & p) {return (inco(p.x,queryX1(),queryX2()) && inco(p.y,queryY1(),queryY2()) && inco(p.z,queryZ1(),queryZ2()));}

	Size3D querySize() const;
	Point3D queryCenter() const;

	real queryX1() const {return minT(a.x,b.x);}
	real queryX2() const {return maxT(a.x,b.x);}
	real queryY1() const {return minT(a.y,b.y);}
	real queryY2() const {return maxT(a.y,b.y);}
	real queryZ1() const {return minT(a.z,b.z);}
	real queryZ2() const {return maxT(a.z,b.z);}

	void serialize(BOStorage &) const;
	void serialize(BIStorage &);
	void serialize(TOStorage &) const;
	void serialize(TIStorage &);
};


Box3D u(const Box3D &, const Box3D &);
#endif

class Tetrahedron : public Serializable
{
	DECLARE_SERIALIZABLE(Tetrahedron)

	private:
	Point3D _a,_b,_c,_d;

	public:
	virtual ~Tetrahedron() {}
	Tetrahedron(const Point3D & a, const Point3D & b, const Point3D & c, const Point3D & d) :
		_a(a), _b(b), _c(c), _d(d) {}
	
	const Point3D baricenter() const
	{
		return Point3D((_a.x()+_b.x()+_c.x()+_d.x())/4,(_a.y()+_b.y()+_c.y()+_d.y())/4,(_a.z()+_b.z()+_c.z()+_d.z())/4);
	}

	real volume() const
	{
		return !Matrix33(_b-_a, _c-_a, _d-_a)/3;
	}

	virtual void serialize(BOStorage &) const;
	virtual void serialize(BIStorage &);
	virtual void serialize(TOStorage &) const;
	virtual void serialize(TIStorage &);
};


class Solid3D : public Serializable  /// solido memorizzato tramite le facce triangolari
{
	DECLARE_SERIALIZABLE(Solid3D)

	public:
	typedef std::vector<Point3D>::size_type t_ndx;

	private:

	class Face : public Serializable
	{
		DECLARE_SERIALIZABLE(Face)
		public:
		t_ndx _n1,_n2,_n3;
		virtual ~Face() {}
		Face() : _n1(0), _n2(0), _n3(0) {}
	
		Face(t_ndx n1, t_ndx n2, t_ndx n3) : _n1(n1), _n2(n2), _n3(n3) {}
		
		virtual void serialize(BOStorage &) const;
		virtual	void serialize(BIStorage &);
		virtual void serialize(TOStorage &) const;
		virtual void serialize(TIStorage &);
	};

	std::vector<Point3D> _vertices;
	std::vector<Face> _faces;

	mutable std::vector<Triangle3D> _cache_faces;
	mutable std::vector<Segment3D> _cache_edges;
	mutable bool _cache_ok_faces;
	mutable bool _cache_ok_edges;

	const std::set<std::pair<t_ndx,t_ndx> > extractEdges() const;
	void computeFaces() const;
	void computeEdges() const;

	void invalidate() {_cache_ok_faces=false,_cache_ok_edges=false;}
	const Point3D vcenter() const;


	public:

	Solid3D() : _cache_ok_faces(false), _cache_ok_edges(false) {}

	t_ndx addVertex(const Point3D & t);
	void addFace(t_ndx n1, t_ndx n2, t_ndx n3);

	bool verify() const;
	const std::vector<Segment3D> & queryEdges() const;
	const std::vector<Triangle3D> & queryFaces() const;	

	Solid3D & operator += (const Vector3D & v);
	const Solid3D operator + (const Vector3D & v) const;

	Solid3D & operator -= (const Vector3D & v);
	const Solid3D operator - (const Vector3D & v) const;

 	Solid3D & operator *= (const Transform3D & v);
	const Solid3D operator * (const Transform3D & v) const;

	const Point3D baricenter() const;
	real volume() const;
	real area() const;

	bool co(const Point3D & p) const;
	void clear();

	virtual void serialize(BOStorage &) const;
	virtual void serialize(BIStorage &);
	virtual void serialize(TOStorage &) const;
	virtual	void serialize(TIStorage &);

};


#if 0
class Tube3D: public Serializable /// tubo memorizzato tramite i vertici delle sezioni
{
	public:

	Tube3D() : _n(0) {}
	explicit Tube3D(size_t n) : _n(n) {}

	void toSolid3D(Solid3D &) const;	// Costruisce un Solid3D 
	void clear(size_t n);

	void serialize(BOStorage &) const;
	void serialize(BIStorage &);
	void serialize(TOStorage &) const;
	void serialize(TIStorage &);

	void addPolygon(const Polygon3D &);

	private:
	size_t _n;		// numero di vertici per sezione
	std::vector<Point3D> _v;	// i vertici di tutte le sezioni
};


class MultiCircularCone3D : public Serializable
{
	public:

	MultiCircularCone3D();
	void toTube3D(Tube3D &, size_t nside) const;
	void add(const Point3D & p, real r); /// aggiunge un tratto al profilo
	void insert(size_t position, const Point3D & p, real r);	/// inserisce un tratto nel profilo
	void erase(size_t position);	/// elimina un tratto dal profilo
	size_t size() const;

	const std::pair<Point3D,real> & operator [](size_t) const;
	std::pair<Point3D,real> & operator [](size_t);

	const Point3D & point(size_t n) const { ASSERT(n<_p.size()); return _p[n].first; }
	Point3D & point(size_t n) { ASSERT(n<_p.size()); return _p[n].first; }

	real radius(size_t n) const { ASSERT(n<_p.size()); return _p[n].second; }
	real& radius(size_t n) { ASSERT(n<_p.size()); return _p[n].second; }

	void serialize(BOStorage &) const;
	void serialize(BIStorage &);
	void serialize(TOStorage &) const;
	void serialize(TIStorage &);

	MultiCircularCone3D operator + (const Vector3D &) const;

	private:

	std::vector<std::pair<Point3D,real> > _p;
};
#endif

class Transform3D : public Serializable
{
	DECLARE_SERIALIZABLE(Transform3D)

	public:

	Transform3D() : _matrix(Matrix33::I) {}
	Transform3D(const Matrix33 & m, const Vector3D & v) : _matrix(m), _vector(v) {}

	const Transform3D operator ~() const;
	const Transform3D operator -() const;
	const Transform3D operator +() const;
	real operator !() const;
	const Transform3D operator *(const Transform3D &) const;

	const Point3D apply(const Point3D &) const;

	static const Transform3D translation(const Vector3D &);
	static const Transform3D rotation(real alfa, const Versor3D &, const Point3D & center);
	static const Transform3D rotation(const Versor3D & v1, const Versor3D & v2, const Point3D & center);
	static const Transform3D scale(real kappa, const Point3D & center);

	void serialize(BOStorage &) const;
	void serialize(BIStorage &);
	void serialize(TOStorage &) const;
	void serialize(TIStorage &);

	
	private:
	Matrix33 _matrix;
	Vector3D _vector;
};


class Polygon3D : public Serializable     /// poligono memorizzato mediante i vertici
{
	DECLARE_SERIALIZABLE(Polygon3D)

	public:
	explicit Polygon3D(size_t n) : _p(n) {}
	Polygon3D() {}

	static Polygon3D regular(size_t);

	void resize(size_t n) { _p.resize(n); }
	size_t size() const { return _p.size(); }

	const Point3D & operator [] (size_t n) const { ASSERT(n<_p.size()); return _p[n]; }
	Point3D & operator [] (size_t n) { ASSERT(n<_p.size()); return _p[n]; }

	real length(void) const;		// perimetro
	//real length(size_t) const;		// lunghezza di un tratto
	
	const Point3D at(real t) const;	// ritorna il punto corrispondente all'ascissa curvilinea t

	Polygon3D & operator += (const Vector3D &);
	Polygon3D operator + (const Vector3D &) const;

	Polygon3D & operator -= (const Vector3D &);
	Polygon3D operator - (const Vector2D &) const;

	Polygon3D & operator *= (const Transform3D &);
	Polygon3D operator * (const Transform3D &) const;

	void serialize(BOStorage &) const;
	void serialize(BIStorage &);
	void serialize(TOStorage &) const;
	void serialize(TIStorage &);


	private:
	std::vector<Point3D> _p;
};



//*//////////////////////////////// globals

inline real triproduct(const Vector3D & v1, const Vector3D & v2, const Vector3D & v3) {return !Matrix33(v1,v2,v3);} // determinante della matrice ottenuta dai tre vettori 

#if 0
inline real sin(const Vector3D & v1, const Vector3D & v2) {return (!(v1^v2)) / ::sqrt(v1.qdr()*v2.qdr());}   // seno dell' angolo compreso tra i due vettori (commutativo)
#endif
inline real cos(const Vector3D & v1, const Vector3D & v2) {return (v1*v2) / ::sqrt(v1.qdr()*v2.qdr());}   // coseno dell' angolo compreso tra i due vettori (commutativo)
#if 0
inline real sin(const Versor3D & v1, const Versor3D & v2) {return (!(Vector3D(v1) ^ Vector3D(v2)));}   // seno dell' angolo compreso tra i due vettori (non commutativo)
#endif
inline real cos(const Versor3D & v1, const Versor3D & v2) {return Vector3D(v1) * Vector3D(v2);}   // coseno dell' angolo compreso tra i due vettori (commutativo)



inline real dist2(const Line3D & a, const Line3D & b) {return ((a.org() - b.org()) | Versor3D::ort(a.dir(),b.dir())).qdr();}
inline real dist(const Line3D & a, const Line3D & b) {return ::sqrt(dist2(a,b));}

real dist2(const Segment3D &, const Segment3D &);
inline real dist(const Segment3D & a, const Segment3D & b) {return ::sqrt(dist2(a,b));}

real dist2(const Triangle3D &, const Triangle3D &);
inline real dist(const Triangle3D & a, const Triangle3D & b) {return ::sqrt(dist2(a,b));}

//real dist2(const Solid3D &, const Solid3D &);
//inline real dist(const Solid3D & a, const Solid3D & b) {return ::sqrt(dist2(a,b));}

inline real dist2(const Point3D & p, const Line3D & r) {return dist2(p,p|r);}
inline real dist(const Point3D & p, const Line3D & r) {return ::sqrt(dist2(p,r));}

inline real dist2(const Point3D & p, const Plane3D & k) {return dist2(p,p|k);}
inline real dist(const Point3D & p, const Plane3D & k) {return ::sqrt(dist2(p,k));}

real dist2(const Point3D &, const Segment3D &);
inline real dist(const Point3D & p, const Segment3D & s) {return ::sqrt(dist2(p,s));}

real dist2(const Point3D &, const Triangle3D &);
inline real dist(const Point3D & p, const Triangle3D & t) {return ::sqrt(dist2(p,t));}

real dist2(const Segment3D &, const Triangle3D &);
inline real dist(const Segment3D & s, const Triangle3D & t) {return ::sqrt(dist2(s,t));}

//real dist(const Point3D &, const Box3D &);
//real dist(const Box3D &, const Box3D &);


Point3D inters(const Line3D & r, const Plane3D & alfa);
Point3D inters(const SemiLine3D & r, const Triangle3D & t);

Point3D inters(const Segment3D & s, const Triangle3D & t);
bool collide(const Segment3D & s, const Triangle3D & t);

real solidAngle(const Versor3D &, const Versor3D &, const Versor3D &);


SGU_NS_END

#endif
